/**
 * Created by KingKong on 2017/8/9.
 */
import {Injectable} from '@angular/core';
import {FormBuilder, FormGroup, ValidatorFn} from '@angular/forms';

import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';

import {formKeyDictionary, formValidateConfig} from '../config/form-validate-config';

import {customizeRequiredValidator} from '../utils/validatorFns/customize-required-validator';
import {customizeRegexValidator} from '../utils/validatorFns/customize-regex-validator';
import {customizeMaxLengthValidator} from '../utils/validatorFns/customize-max-length-validator';
import {customizeMinLengthValidator} from '../utils/validatorFns/customize-min-length-validator';
import {customizeMinValueValidator} from '../utils/validatorFns/customize-min-value-validator';
import {customizeMaxValueValidator} from '../utils/validatorFns/customize-max-value-validator';
import {customizeEqualToValidator} from '../utils/validatorFns/customize-equal-to-validator';
import {customizeDateTimeValidator} from "../utils/validatorFns/customize-datetime-validator";


@Injectable()
export class CustomizeFormValidateService {
  constructor() {
  }

  /**
   * 构建表单验证
   * @param component
   * @param serverFormName serverFormName为空，则不去后端获取验证规则
   */
  buildForm(component: any, serverFormName?: string): void {
    if (!component.formName) {
      throw new Error('未指定表单名');
    }

    if (!component.formModel) {
      throw new Error('表单实体类未实例化');
    }

    const keyList = formKeyDictionary[component.formName];
    if (!keyList) {
      throw new Error('表单配置项列表不存在');
    }

    // 构造表单依赖的数据
    const fb = new FormBuilder(), config = {};
    component.formErrors = {};
    component.formPlaceholder = {};
    component.validationMessages = {};
    // 遍历表单配置项
    keyList.forEach(item => {
      if (!component.formModel[item]) {
        component.formModel[item] = null;
      }
      component.formErrors[item] = '';
      component.formPlaceholder[item] = '';
      component.validationMessages[item] = {};
      config[item] = [component.formModel[item], null];
    });

    // 使用表单配置项同步生成表单
    component.formGroup = fb.group(config);

    if (serverFormName) {
      this.getFormConfigAsync(serverFormName).subscribe(t => {
        this.generateFormConfig(t, component);
      });
    } else {
      this.generateFormConfig(this.getFormConfig(component.formName), component);
    }
  }

  /**获取表单配置的同步函数，用来获取程序里的配置信息*/
  getFormConfig(formName: string): FormValidatorVO[] {
    return formValidateConfig[formName];
  }

  /**获取表单配置的异步函数，用来获取服务器后端里的表单配置信息*/
  getFormConfigAsync(formName: string): Observable<FormValidatorVO[]> {
    return Observable.create((observer: Observer<FormValidatorVO[]>) => {
      observer.next(formValidateConfig[formName]);
    });
  }

  generateFormConfig(config: FormValidatorVO[], component: any) {
    config.forEach((validateItem) => {
      const item: FormValidatorVO = <FormValidatorVO>validateItem;

      // 添加placeholder
      if (item.placeHolder !== null) {
        component.formPlaceholder[item.fieldCode] = item.placeHolder;
      }

      // 添加所有可能出现错误提示信息
      if (item.hasOwnProperty('requiredMessage') && item.requiredMessage !== null && item.requiredMessage !== '') {
        component.validationMessages[item.fieldCode]['required'] = item.requiredMessage;
      }
      if (item.hasOwnProperty('regexMessage') && item.regexMessage !== null && item.regexMessage !== '') {
        component.validationMessages[item.fieldCode]['regex'] = item.regexMessage;
      }
      if (item.hasOwnProperty('maxLengthMessage') && item.maxLengthMessage !== null && item.maxLengthMessage !== '') {
        component.validationMessages[item.fieldCode]['maxLength'] = item.maxLengthMessage;
      }
      if (item.hasOwnProperty('minLengthMessage') && item.minLengthMessage !== null && item.minLengthMessage !== '') {
        component.validationMessages[item.fieldCode]['minLength'] = item.minLengthMessage;
      }
      if (item.hasOwnProperty('maxValueMessage') && item.maxValueMessage !== null && item.maxValueMessage !== '') {
        component.validationMessages[item.fieldCode]['maxValue'] = item.maxValueMessage;
      }
      if (item.hasOwnProperty('minValueMessage') && item.minValueMessage !== null && item.minValueMessage !== '') {
        component.validationMessages[item.fieldCode]['minValue'] = item.minValueMessage;
      }
      if (item.hasOwnProperty('timeMessage') && item.timeMessage !== null && item.timeMessage !== '') {
        component.validationMessages[item.fieldCode]['time'] = item.timeMessage;
      }
      if (item.hasOwnProperty('equalToMessage') && item.equalToMessage !== null && item.equalToMessage !== '') {
        component.validationMessages[item.fieldCode]['equalTo'] = item.equalToMessage;
      }

      // 获取当前遍历项有哪些验证规则
      const validatorTypeList: { [key: string]: string } = {};

      if (item.hasOwnProperty('required') && item.required !== null && item.required !== false) {
        validatorTypeList['required'] = '';
      }
      if (item.hasOwnProperty('regex') && item.regex !== null) {
        validatorTypeList['regex'] = '';
      }
      if (item.hasOwnProperty('maxLength') && item.maxLength !== null) {
        validatorTypeList['maxLength'] = '';
      }
      if (item.hasOwnProperty('minLength') && item.minLength !== null) {
        validatorTypeList['minLength'] = '';
      }
      if (item.hasOwnProperty('maxValue') && item.maxValue !== null) {
        validatorTypeList['maxValue'] = '';
      }
      if (item.hasOwnProperty('minValue') && item.minValue !== null) {
        validatorTypeList['minValue'] = '';
      }
      if (item.hasOwnProperty('time') && item.time !== null) {
        validatorTypeList['time'] = '';
      }
      if (item.hasOwnProperty('equalTo') && item.equalTo !== null) {
        validatorTypeList['equalTo'] = '';
      }

      // 声明验证规则列表
      const validatorList: ValidatorFn[] = [];
      // 添加验证规则
      if (item.hasOwnProperty('required') && item.required !== null && item.required !== false) {
        validatorList.push(customizeRequiredValidator('required'));
      }
      if (item.hasOwnProperty('regex') && item.regex !== null) {
        validatorList.push(customizeRegexValidator(new RegExp(item.regex), validatorTypeList, 'regex'));
      }
      if (item.hasOwnProperty('maxLength') && item.maxLength !== null) {
        validatorList.push(customizeMaxLengthValidator(item.maxLength, 'maxLength'));
      }
      if (item.hasOwnProperty('minLength') && item.minLength !== null) {
        validatorList.push(customizeMinLengthValidator(item.minLength, validatorTypeList, 'minLength'));
      }
      if (item.hasOwnProperty('maxValue') && item.maxValue !== null) {
        validatorList.push(customizeMaxValueValidator(item.maxValue, 'maxValue'));
      }
      if (item.hasOwnProperty('minValue') && item.minValue !== null) {
        validatorList.push(customizeMinValueValidator(item.minValue, validatorTypeList, 'minValue'));
      }
      if (item.hasOwnProperty('time') && item.time !== null) {
        validatorList.push(customizeDateTimeValidator(validatorTypeList, 'time'));
      }
      if (item.hasOwnProperty('equalTo') && item.equalTo !== null) {
        validatorList.push(customizeEqualToValidator(item.equalTo, 'equalTo'));
      }

      // 为表单项应用验证规则
      component.formGroup.get(item.fieldCode).setValidators(validatorList);
    });

    // 取出所有应用验证规则的表单项的键集合
    const arr: string[] = Object.keys(component.formGroup.controls);

    // 每个表单项的更改事件里写入表单实体
    arr.forEach(item => {
      component.formGroup.get(item).valueChanges.subscribe(data => {
        component.formModel[item] = data;
        validatorMessageFn(component.formGroup, component.formErrors, component.validationMessages, item);
      });
    });

    // 将页面创建的实体，一次性写入到表单中
    component.formGroup.patchValue(component.formModel);
  }
}

/** 表单验证组件的接口类，自动生成表单需要的属性变量 */
export declare interface ICustomizeFormValidate {
  // 表单名
  formName: string;
  // 表单
  formGroup: FormGroup;
// 表单实体
  formModel: any;
  // 错误信息键值对
  formErrors: { [key: string]: string };
  // 占位符键值对
  formPlaceholder: { [key: string]: string };
  // 左右验证信息键值对
  validationMessages: { [key: string]: { [key: string]: string } };
}

export class FormValidatorVO {
  /**字段名*/
  fieldCode: string;
  /**字段标题*/
  fieldName: string;
  /**必填项*/
  required?: boolean;
  /**验证失败的提示信息*/
  requiredMessage?: string;
  /**最大长度*/
  maxLength?: number;
  /**最大长度验证失败的提示信息*/
  maxLengthMessage?: string;
  /**最小长度*/
  minLength?: number;
  /**最小长度验证失败的提示信息*/
  minLengthMessage?: string;
  /**最大值*/
  maxValue?: number;
  /**最大值验证失败的提示信息*/
  maxValueMessage?: string;
  /**最小值*/
  minValue?: number;
  /**最小值验证失败的提示信息*/
  minValueMessage?: string;
  /**比较字段*/
  equalTo?: string;
  /**比较字段验证失败的提示信息*/
  equalToMessage?: string;
  /**正则验证规则*/
  regex?: string;
  /**正则验证失败的提示信息*/
  regexMessage?: string;
  /**日期验证规则*/
  time?: boolean;
  /**日期验证失败的提示信息*/
  timeMessage?: string;
  /**占位符*/
  placeHolder?: string;
}

// 错误信息的排序规则，靠前的错误提示优先显示
const validationOrder: string[] = ['required', 'regex', 'maxLength', 'minLength', 'maxValue', 'minValue', 'equalTo'];

function validatorMessageFn(form: any, formErrors: any, validationMessages, field: string) {
  if (!form) {
    return;
  }
  if (formErrors && formErrors.hasOwnProperty(field)) {
    formErrors[field] = '';
    const control = form.get(field);

    if (control && control.dirty && !control.valid) {
      const messages = validationMessages[field];
      for (const obj of validationOrder) {
        if (control.errors && control.errors.hasOwnProperty(obj)) {
          (formErrors[field] = messages[obj] + '');
          break;
        }
      }
    }
  }
}
